﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace Yxinmt.SmarterStreaming
{
    public static class NTSmartPublisherDefine
    {
        public const int NT_PB_IMAGE_MAX_PLANE_NUM = 16;

        public const int NT_PB_CAMERA_UNIQUE_ID_UTF8_MAX_SIZE = 1024; // 摄像头唯一ID最大值是1023字符, 再加一个0
        public const int NT_PB_MAX_FILE_PATH_LENGTH = 2048;           // 最大文件路径限制,注意还需要包括个0

        /*错误码*/
        public enum NT_PB_E_ERROR_CODE : uint
        {
            NT_ERC_PB_HWND_IS_NULL = (NTBaseCodeDefine.NT_ERC_SMART_PUBLISHER_SDK | 0x1),  // 窗口句柄是空
            NT_ERC_PB_HWND_INVALID = (NTBaseCodeDefine.NT_ERC_SMART_PUBLISHER_SDK | 0x2),  // 窗口句柄无效
            NT_ERC_PB_DIR_NOT_EXIST = (NTBaseCodeDefine.NT_ERC_SMART_PUBLISHER_SDK | 0x3), // 目录不存在
            NT_ERC_PB_INVALID_SCREEN_RECTREGION = (NTBaseCodeDefine.NT_ERC_SMART_PUBLISHER_SDK | 0x4), // 无效的屏幕矩形区域
            NT_ERC_PB_URL_EXIST = (NTBaseCodeDefine.NT_ERC_SMART_PUBLISHER_SDK | 0x5),     // 推送URL已经存在
            NT_ERC_PB_NO_IMAGE = (NTBaseCodeDefine.NT_ERC_SMART_PUBLISHER_SDK | 0x6),      // 没有图像
            NT_ERC_PB_TOO_MANY_CAPTURE_IMAGE_REQUESTS = (NTBaseCodeDefine.NT_ERC_SMART_PLAYER_SDK | 0x7),   // 太多的截图请求
        }

        /*事件ID*/
        public enum NT_PB_E_EVENT_ID : uint
        {
            NT_PB_E_EVENT_ID_BASE = NTBaseCodeDefine.NT_EVENT_ID_SMART_PUBLISHER_SDK,

            NT_PB_E_EVENT_ID_CONNECTING = NT_PB_E_EVENT_ID_BASE | 0x2,	/*连接中, param5表示推送URL */
            NT_PB_E_EVENT_ID_CONNECTION_FAILED = NT_PB_E_EVENT_ID_BASE | 0x3,	/*连接失败, param5表示推送URL*/
            NT_PB_E_EVENT_ID_CONNECTED = NT_PB_E_EVENT_ID_BASE | 0x4,	/*已连接, param5表示推送URL*/
            NT_PB_E_EVENT_ID_DISCONNECTED = NT_PB_E_EVENT_ID_BASE | 0x5,	/*断开连接, param5表示推送URL*/

            NT_PB_E_EVENT_ID_RECORDER_START_NEW_FILE = NT_PB_E_EVENT_ID_BASE | 0x7,	/*录像写入新文件, param5表示录像文件名*/
            NT_PB_E_EVENT_ID_ONE_RECORDER_FILE_FINISHED = NT_PB_E_EVENT_ID_BASE | 0x8,	/*一个录像文件完成, param5表示录像文件名*/

        }



        /*设置参数ID, 这个目前这么写，SmartPlayerSDK 已经划分范围*/
        public enum NT_PB_E_PARAM_ID : uint
        {
            NT_PB_PARAM_ID_BASE = NTBaseCodeDefine.NT_PARAM_ID_SMART_PUBLISHER_SDK,
        }

        /*定义Video源选项*/
        public enum NT_PB_E_VIDEO_OPTION : uint
        {
            NT_PB_E_VIDEO_OPTION_NO_VIDEO = 0x0,
            NT_PB_E_VIDEO_OPTION_SCREEN = 0x1, // 采集屏幕
            NT_PB_E_VIDEO_OPTION_CAMERA = 0x2, // 摄像头采集
            NT_PB_E_VIDEO_OPTION_LAYER = 0x3,  // 视频合并，比如桌面叠加摄像头等
            NT_PB_E_VIDEO_OPTION_ENCODED_DATA = 0x4, // 已经编码的视频数据，目前支持H264
        }

        /*定义Auido源选项*/
        public enum NT_PB_E_AUDIO_OPTION : uint
        {
            NT_PB_E_AUDIO_OPTION_NO_AUDIO = 0x0,
            NT_PB_E_AUDIO_OPTION_CAPTURE_MIC = 0x1,           // 采集麦克风音频
            NT_PB_E_AUDIO_OPTION_CAPTURE_SPEAKER = 0x2,           // 采集扬声器
            NT_PB_E_AUDIO_OPTION_CAPTURE_MIC_SPEAKER_MIXER = 0x3,    // 麦克风扬声器混音
            NT_PB_E_AUDIO_OPTION_ENCODED_DATA = 0x4, // 编码后的音频数据，目前支持AAC, speex宽带(wideband mode)
        }

        /*屏幕区域选择消息ID*/
        public enum NT_PB_E_SCREEN_REGION_CHOOSE_MSG_ID : uint
        {
            NT_PB_E_SCREEN_REGION_CHOOSE_MSG_CANCEL = 1,    // 取消选择， 用户按了ESC键, 或者用户双击但是没有选择任何区域
            NT_PB_E_SCREEN_REGION_CHOOSE_MSG_OK = 2,        // 选择成功
            NT_PB_E_SCREEN_REGION_CHOOSE_MSG_MOVE = 3,      // 用户移动区域, 这个只在移动模式下才会发送这个消息
        }

        /*屏幕区域选择模式*/
        public enum NT_PB_E_SCREEN_REGION_CHOOSE_MODE : uint
        {
            NT_PB_E_SCREEN_REGION_CHOOSE_MODE_CHOOSE = 1, // 当前是选择模式
            NT_PB_E_SCREEN_REGION_CHOOSE_MODE_MOVE = 2, // 当前是移动模式
        }

        /*Image格式*/
        public enum NT_PB_E_IMAGE_FORMAT : uint
        {
            NT_PB_E_IMAGE_FORMAT_RGB32 = 1, // 32位的rgb格式, r, g, b各占8, 另外一个字节保留, 内存字节格式为: bb gg rr xx, 主要是和windows位图匹配, 在小端模式下，按DWORD类型操作，最高位是xx, 依次是rr, gg, bb
            NT_PB_E_IMAGE_FORMAT_ARGB = 2, // 32位的argb格式，内存字节格式是: bb gg rr aa 这种类型，和windows位图匹配
            NT_PB_E_IMAGE_FORMAT_I420 = 3, // YUV420格式, 三个分量保存在三个面上
        }

        /*视频合成时，每一层的类型*/
        public enum NT_PB_E_LAYER_TYPE : int
        {
            NT_PB_E_LAYER_TYPE_SCREEN = 1,                  // 屏幕层
            NT_PB_E_LAYER_TYPE_CAMERA = 2,                  // 摄像头层
            NT_PB_E_LAYER_TYPE_RGBA_RECTANGLE = 3,          // RGBA矩形
            NT_PB_E_LAYER_TYPE_IMAGE = 4,                   // 图片层
            NT_PB_E_LAYER_TYPE_EXTERNAL_VIDEO_FRAME = 5,    // 外部视频数据层
        }

        /*推送状态*/
        public enum NT_PB_E_PUBLISHER_STATUS : int
        {
            NT_PB_E_PUBLISHER_STATUS_CONNECTING = 1001, /*连接中*/
            NT_PB_E_PUBLISHER_STATUS_CONNECTION_FAILED, /*连接失败*/
            NT_PB_E_PUBLISHER_STATUS_CONNECTED,         /*已连接*/
            NT_PB_E_PUBLISHER_STATUS_DISCONNECTED,      /*断开连接*/
        }
    }

    /*如果三项都是0的话，将不能启动录像*/
    [StructLayoutAttribute(LayoutKind.Sequential)]
    public struct NT_PB_RecorderFileNameRuler
    {
        public UInt32 type_;                                          // 这个值目前默认是0，将来扩展用
        [MarshalAs(UnmanagedType.LPStr)]
        public String file_name_prefix_;                              // 设置一个录像文件名前缀, 例如:daniulive
        public Int32 append_date_;                                    // 如果是1的话，将在文件名上加日期, 例如:daniulive-2017-01-17
        public Int32 append_time_;                                    // 如果是1的话，将增加时间，例如:daniulive-2017-01-17-17-10-36
    }

    /*这个目前只获取摄像头分辨率列表*/
    [StructLayoutAttribute(LayoutKind.Sequential)]
    public struct NT_PB_VideoCaptureCapability
    {
        public Int32 width_;
        public Int32 height_;
        public Int32 max_frame_rate_;
    }

    /*矩形局域*/
    [StructLayoutAttribute(LayoutKind.Sequential)]
    public struct NT_PB_RectRegion
    {
        public Int32 x_;
        public Int32 y_;
        public Int32 width_;
        public Int32 height_;
    }

    /*定义图像数据结构.
     * 图像始终是自上而下的方式, 如果要自下而上的话， 后续考虑height_可以取负值，这正好和位图默认的方式相反
     *  对plane_的操作，请使用SDK提供的接口
     *  这个结构体的创建，释放，SDK都提供了相关接口
     */
    [StructLayoutAttribute(LayoutKind.Sequential)]
    public struct NT_PB_Image
    {
        public UInt32 cb_size_; // 这个结构体的大小
        public Int32 format_;  // 图像格式, 请参考NT_PB_E_IMAGE_FORMAT
        public Int32 width_;   // 图像宽
        public Int32 height_;  // 图像高
        public UInt64 timestamp_; // 时间戳, 一般是0,不使用, 以ms为单位的
        // 具体的图像数据, 一般只用第一个
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = NTSmartPublisherDefine.NT_PB_IMAGE_MAX_PLANE_NUM)]
        public Byte[] plane_;
        // 每一个平面的每一行的字节数，对于argb和rgb32，为了保持和windows位图兼容，必须是width_*4
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = NTSmartPublisherDefine.NT_PB_IMAGE_MAX_PLANE_NUM)]
        public Int32[] stride_;
        // 每一个平面的数据大小, 这个可以根据stride_[i]*abs(height_)计算出来
        // 不同格式的计算方式可能不同
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = NTSmartPublisherDefine.NT_PB_IMAGE_MAX_PLANE_NUM)]
        public Int32[] plane_size_;

    }

    /*合成层的基本类型*/
    [StructLayoutAttribute(LayoutKind.Sequential)]
    public struct NT_PB_LayerBaseConfig
    {
        public Int32 type_;               // 这个是类型, 具体类型请看NT_PB_E_LAYER_TYPE
        public Int32 index_;              // 层索引, 从0开始
        public Int32 enable_;             // 第0层会忽略这个参数， 1:表示启用， 0表示禁用，其他值将报错
        public NT_PB_RectRegion region_;  // 第0层会忽略x, y，宽高将是视频分辨率.
        public UInt32 cb_size_;           // 这个填充真正类型的大小
        public Int32 offset_;             // 这个是一个偏移量，这个偏移量+这个结构体的指针，就能算出真正的类型指针. 比如 NT_PB_LayerBase* p; 那么真正的类型地址就是ActualType* pType= (ActualType*)((char*)p + offset_)
    }

    // 屏幕层, 运行过程中, 只能修改clip_region_.x_ 和 clip_region_.x_，其他值一律不能修改
    // base_.type_ 是 NT_PB_E_LAYER_TYPE_SCREEN
    [StructLayoutAttribute(LayoutKind.Sequential)]
    public struct NT_PB_ScreenLayerConfig
    {
        public NT_PB_LayerBaseConfig base_;
        public NT_PB_RectRegion clip_region_;   // 如果是全屏幕的话，请全部填充0
        public IntPtr reserve_;                 // 保留字段
    }

    // 摄像头层, 运行过程中，任何值都不能修改
    // base_.type_ 是 NT_PB_E_LAYER_TYPE_CAMERA
    [StructLayoutAttribute(LayoutKind.Sequential)]
    public struct NT_PB_CameraLayerConfig
    {
        public NT_PB_LayerBaseConfig base_;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NTSmartPublisherDefine.NT_PB_CAMERA_UNIQUE_ID_UTF8_MAX_SIZE)]
        public String device_unique_id_utf8_;
    }

    // RGB矩形层, 运行过程中，可以修改red_, green_, blue_, 和 alpha_，其他不能修改
    // base_.type_ 是 NT_PB_E_LAYER_TYPE_RGBA_RECTANGLE
    [StructLayoutAttribute(LayoutKind.Sequential)]
    public struct NT_PB_RGBARectangleLayerConfig
    {
        public NT_PB_LayerBaseConfig base_;
        public Byte red_;		// 红色分量
        public Byte green_;	    // 绿色分量
        public Byte blue_;      // 蓝色分量
        public Byte alpha_;	    // Alpha通道, 0是完全透明, 255是完全不透明, 注意：如果是第0层的话，这个值将被忽略
    }

    // 图像层， 运行过程中，任何值都不可以修改
    // base_.type_ 是 NT_PB_E_LAYER_TYPE_IMAGE
    // 目前只支持PNG
    [StructLayoutAttribute(LayoutKind.Sequential)]
    public struct NT_PB_ImageLayerConfig
    {
        public NT_PB_LayerBaseConfig base_;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NTSmartPublisherDefine.NT_PB_MAX_FILE_PATH_LENGTH)]
        public String file_name_utf8_;
        public Int32 is_setting_background_;   // 是否设置了背景, 1：表示设置, 0:表示没有设置. 其他错误. 如果是第0层，不设置背景的话，将会使用白色作为默认背景, 其他层最好不要设置背景，不然不透明了
        public Byte bk_red_;                   // 红色分量 
        public Byte bk_green_;                 // 绿色分量
        public Byte bk_blue_;                  // 蓝色分量
        public Int32 reserve_;                 // 保留，填充0就可以
    }

    // 外部视频数据层
    // base_.type_ 是 NT_PB_E_LAYER_TYPE_EXTERNAL_VIDEO_FRAME
    // 这个层支持外部传入yuv或者rgb数据给sdk
    [StructLayoutAttribute(LayoutKind.Sequential)]
    public struct NT_PB_ExternalVideoFrameLayerConfig
    {
        public NT_PB_LayerBaseConfig base_;
    }

    /*
     * 屏幕区域选择工具CallBack
     * msg_id: 请参考NT_PB_E_SCREEN_REGION_CHOOSE_MSG_ID
     * msg_data: msg_id == NT_PB_E_SCREEN_REGION_CHOOSE_MSG_CANCEL, msg_data 是NULL
     * msg_id == NT_PB_E_SCREEN_REGION_CHOOSE_MSG_OK, msg_data 是NT_PB_RectRegion*
     * msg_id == NT_PB_E_SCREEN_REGION_CHOOSE_MSG_MOVE, msg_data是NT_PB_RectRegion*
     */
    [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)]
    public delegate void NT_PB_SDKScreenRegionChooseCallBack(IntPtr tool_handle, IntPtr userData,
        UInt32 msg_id, IntPtr msg_data);

    /*
     * 推送SDK, 截屏回调
     * result: 如果截屏成功的话，result是NT_ERC_OK,其他错误
     */
    [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)]
    public delegate void NT_PB_SDKCaptureImageCallBack(IntPtr handle, IntPtr userData,
        UInt32 result, [MarshalAs(UnmanagedType.LPStr)] String file_name);

    /*
     * 当发送rtmp视频包时，会回调, 注意：请不要在回调函数里面做耗时的事情，这样会卡住发包线程
     * handle: 推送句柄
     * userData: 用户自定义数据
     * url:推送URL，主要用在推送多个url时，进行区分
     * is_changed:时间戳是否改变, 1:表示改变, 0:表示未改变
     * timestamp:时间戳(单位是毫秒)
     * reserve1:保留参数
     * reserve2:保留参数
     */
    [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)]
    public delegate void NT_PB_SDKVideoPacketTimestampCallBack(IntPtr handle, IntPtr userData,
        [MarshalAs(UnmanagedType.LPStr)] String url, Int32 is_changed, UInt64 timestamp, UInt64 reserve1, IntPtr reserve2);

    /*
     * 推送状态回调
     * handle: 推送句柄
     * user_data: 用户数据
     * url: 推送URL
     * status: 推送状态请参考 NT_PB_E_PUBLISHER_STATUS
     */
    [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)]
    public delegate void NT_PB_SDKPublisherStatusCallBack(IntPtr handle, IntPtr user_data,
        [MarshalAs(UnmanagedType.LPStr)] String url, UInt32 status);

    /*
     * 推送事件回调
     * event_id: 事件ID，请参考NT_PB_E_EVENT_ID
     * param1 到 param7, 值的意义和具体事件ID相关, 注意如果具体事件ID没有说明param1-param7的含义，那说明这个事件不带参数
     */
    [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)]
    public delegate void NT_PB_SDKEventCallBack(IntPtr handle, IntPtr user_data,
        UInt32 event_id,
        Int64 param1,
        Int64 param2,
        UInt64 param3,
        UInt64 param4,
        [MarshalAs(UnmanagedType.LPStr)] String param5,
        [MarshalAs(UnmanagedType.LPStr)] String param6,
        IntPtr param7
        );
}
